#define A(i, j) A[(i) + (j) * (LDA)]
#define B(i, j) B[(i) + (j) * (LDB)]
#define C(i, j) C[(i) + (j) * (LDC)]

static void mm_v4_corner(int M, int N, int K, double *A, int LDA, double *B,
                         int LDB, double *C, int LDC) {
    double tmp = 0;
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            tmp = 0;
            for (int k = 0; k < K; k++) {
                tmp += A(i, k) * B(k, j);
            }
            C(i, j) = tmp;
        }
    }
}
// 重复利用寄存器 4x4分块
// A:[M, K] B:[K, N] C:[M, N]
inline void mm_v4(int M, int N, int K, double *A, int LDA, double *B, int LDB,
                  double *C, int LDC) {
    int m4 = M & -4;
    int n4 = N & -4;
    for (int i = 0; i < m4; i += 4) {
        for (int j = 0; j < n4; j += 4) {
            double c00 = 0;
            double c01 = 0;
            double c02 = 0;
            double c03 = 0;
            double c10 = 0;
            double c11 = 0;
            double c12 = 0;
            double c13 = 0;
            double c20 = 0;
            double c21 = 0;
            double c22 = 0;
            double c23 = 0;
            double c30 = 0;
            double c31 = 0;
            double c32 = 0;
            double c33 = 0;

            for (int k = 0; k < K; k++) {
                double a0 = A(i, k);
                double a1 = A(i + 1, k);
                double a2 = A(i + 2, k);
                double a3 = A(i + 3, k);
                double b0 = B(k, j);
                double b1 = B(k, j + 1);
                double b2 = B(k, j + 2);
                double b3 = B(k, j + 3);

                c00 += a0 * b0;
                c01 += a0 * b1;
                c02 += a0 * b2;
                c03 += a0 * b3;
                c10 += a1 * b0;
                c11 += a1 * b1;
                c12 += a1 * b2;
                c13 += a1 * b3;
                c20 += a2 * b0;
                c21 += a2 * b1;
                c22 += a2 * b2;
                c23 += a2 * b3;
                c30 += a3 * b0;
                c31 += a3 * b1;
                c32 += a3 * b2;
                c33 += a3 * b3;
            }
            C(i, j) = c00;
            C(i, j + 1) = c01;
            C(i, j + 2) = c02;
            C(i, j + 3) = c03;
            C(i + 1, j) = c10;
            C(i + 1, j + 1) = c11;
            C(i + 1, j + 2) = c12;
            C(i + 1, j + 3) = c13;
            C(i + 2, j) = c20;
            C(i + 2, j + 1) = c21;
            C(i + 2, j + 2) = c22;
            C(i + 2, j + 3) = c23;
            C(i + 3, j) = c30;
            C(i + 3, j + 1) = c31;
            C(i + 3, j + 2) = c32;
            C(i + 3, j + 3) = c33;
        }
    }
    if (M == m4 && N == n4) {
        return;
    }
    if (M != m4) {
        mm_v4_corner(M - m4, N, K, &A(m4, 0), LDA, &B(0, 0), LDB, &C(m4, 0),
                     LDC);
    }
    if (N != n4) {
        mm_v4_corner(m4, N - n4, K, &A(0, 0), LDA, &B(0, n4), LDB, &C(0, n4),
                     LDC);
    }
}
#undef A
#undef B
#undef C
